﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Audit.Generators
{
    public abstract class Generator
    {
        protected uint Count = 1000;            //count of elemnts(default: 1000)
        protected Array Args;                    //arguments of generator
        protected uint Index;                   //current index of array
        protected double[] Variables;               //array of random variables arranged under distribution
        protected bool Initialised = false;     //flag, which show, that args and parametrs are installed

        /// <summary>
        /// Install Parametrs of generator(count by default)
        /// </summary>
        /// <param name="_args">Parametrs for Generator</param>
        /// <returns>Raturns generator with initiallised prametrs</returns>
        public Generator InitGenerator(Array _args)
        {
            if (ValidateArgs(_args))
            {
                Args = _args;
                Index = 0;
                Variables = new double[Count];
                Initialised = true;

                Generate();
            }
            else
                throw new Exception();

            return this;
        }

        /// <summary>
        /// Install Parametrs of generator
        /// </summary>
        /// <param name="_count">Count of generating variables at first</param>
        /// <param name="_args">Parametrs for Generator</param>
        /// <returns>Raturns generator with initiallised prametrs</returns>
        public Generator InitGenerator(uint _count, Array _args)
        {
            if (ValidateArgs(_args))                                //args validating
            {
                Count = _count;
                Args = _args;
                Index = 0;
                Variables = new double[Count];
                Initialised = true;                                 //flag on - parametrs are initiallised

                Generate();
            }
            else
                throw new Exception();

            return this;
        }

        /// <summary>
        /// Return information about initiallisation of generator
        /// </summary>
        /// <returns>True if parametrs are initialised</returns>
        public bool IsInitialised()
        {
            return Initialised;
        }

        /// <summary> 
        /// Generate variables arranged under distribution
        /// </summary>
        protected abstract void Generate();

        /// <summary>
        /// Check input args for current distribution
        /// </summary>
        /// <param name="_args">Parametrs for generator</param>
        /// <returns>True if all args are not erratic</returns>
        protected abstract bool ValidateArgs(Array _args);

        /// <summary>
        /// Returns next random variable arranged under distribution
        /// </summary>
        /// <returns>New Variable under Distribution</returns>
        public double NextVariable()
        {
            if (Initialised)
            {
                if (Index >= Variables.Length)
                {
                    Count *= 2;
                    Index = 0;
                    Variables = new double[Count];
                    Generate();
                }

                return Variables[Index++];
            }
            else
                throw new Exception();
        }

        /// <summary>
        /// Returns array of random variables arranged under distribution
        /// </summary>
        /// <param name="_length">Length of returned array</param>
        /// <returns>Array with random variables</returns>
        public double[] GetArray(uint _length)
        {
            double[] result_;
            uint count_ = Count;

            Count = _length;
            Generate();
            result_ = Variables;

            Count = count_;
            Generate();
            Index = 0;

            return result_;
        }

    }
}
